home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 24 / CU Amiga Magazine's Super CD-ROM 24 (1998)(EMAP Images)(GB)(Track 1 of 2)[!][issue 1998-07].iso / CUCD / Utilities / vim-5.1 / src / memfile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-07  |  29.3 KB  |  1,181 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved    by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  */
  8.  
  9. /*
  10.  * memfile.c: Contains the functions for handling blocks of memory which can
  11.  * be stored in a file. This is the implementation of a sort of virtual memory.
  12.  *
  13.  * A memfile consists of a sequence of blocks. The blocks numbered from 0
  14.  * upwards have been assigned a place in the actual file. The block number
  15.  * is equal to the page number in the file. The
  16.  * blocks with negative numbers are currently in memory only. They can be
  17.  * assigned a place in the file when too much memory is being used. At that
  18.  * moment they get a new, positive, number. A list is used for translation of
  19.  * negative to positive numbers.
  20.  *
  21.  * The size of a block is a multiple of a page size, normally the page size of
  22.  * the device the file is on. Most blocks are 1 page long. A Block of multiple
  23.  * pages is used for a line that does not fit in a single page.
  24.  *
  25.  * Each block can be in memory and/or in a file. The block stays in memory
  26.  * as long as it is locked. If it is no longer locked it can be swapped out to
  27.  * the file. It is only written to the file if it has been changed.
  28.  *
  29.  * Under normal operation the file is created when opening the memory file and
  30.  * deleted when closing the memory file. Only with recovery an existing memory
  31.  * file is opened.
  32.  */
  33.  
  34. #if defined MSDOS || defined WIN32
  35. # include <io.h>    /* for lseek(), must be before vim.h */
  36. #endif
  37.  
  38. #include "vim.h"
  39.  
  40. #ifdef HAVE_FCNTL_H
  41. # include <fcntl.h>
  42. #endif
  43.  
  44. /*
  45.  * Some systems have the page size in statfs.f_bsize, some in stat.st_blksize
  46.  */
  47. #ifdef HAVE_ST_BLKSIZE
  48. # define STATFS stat
  49. # define F_BSIZE st_blksize
  50. # define fstatfs(fd, buf, len, nul) fstat((fd), (buf))
  51. #else
  52. # ifdef HAVE_SYS_STATFS_H
  53. #  include <sys/statfs.h>
  54. #  define STATFS statfs
  55. #  define F_BSIZE f_bsize
  56. #  ifdef __MINT__        /* do we still need this? */
  57. #   define fstatfs(fd, buf, len, nul) fstat((fd), (buf))
  58. #  endif
  59. # endif
  60. #endif
  61.  
  62. /*
  63.  * for Amiga Dos 2.0x we use Flush
  64.  */
  65. #ifdef AMIGA
  66. # ifndef NO_ARP
  67. extern int dos2;            /* this is in os_amiga.c */
  68. # endif
  69. # ifdef SASC
  70. #  include <proto/dos.h>
  71. #  include <ios1.h>            /* for chkufb() */
  72. # endif
  73. #endif
  74.  
  75. #define MEMFILE_PAGE_SIZE 4096        /* default page size */
  76.  
  77. static long_u total_mem_used = 0;    /* total memory used for memfiles */
  78.  
  79. static void mf_ins_hash __ARGS((MEMFILE *, BHDR *));
  80. static void mf_rem_hash __ARGS((MEMFILE *, BHDR *));
  81. static BHDR *mf_find_hash __ARGS((MEMFILE *, blocknr_t));
  82. static void mf_ins_used __ARGS((MEMFILE *, BHDR *));
  83. static void mf_rem_used __ARGS((MEMFILE *, BHDR *));
  84. static BHDR *mf_release __ARGS((MEMFILE *, int));
  85. static BHDR *mf_alloc_bhdr __ARGS((MEMFILE *, int));
  86. static void mf_free_bhdr __ARGS((BHDR *));
  87. static void mf_ins_free __ARGS((MEMFILE *, BHDR *));
  88. static BHDR *mf_rem_free __ARGS((MEMFILE *));
  89. static int  mf_read __ARGS((MEMFILE *, BHDR *));
  90. static int  mf_write __ARGS((MEMFILE *, BHDR *));
  91. static int  mf_trans_add __ARGS((MEMFILE *, BHDR *));
  92. static void mf_do_open __ARGS((MEMFILE *, char_u *, int));
  93.  
  94. /*
  95.  * The functions for using a memfile:
  96.  *
  97.  * mf_open()        open a new or existing memfile
  98.  * mf_open_file()   open a swap file for an existing memfile
  99.  * mf_close()        close (and delete) a memfile
  100.  * mf_new()        create a new block in a memfile and lock it
  101.  * mf_get()        get an existing block and lock it
  102.  * mf_put()        unlock a block, may be marked for writing
  103.  * mf_free()        remove a block
  104.  * mf_sync()        sync changed parts of memfile to disk
  105.  * mf_release_all() release as much memory as possible
  106.  * mf_trans_del()   may translate negative to positive block number
  107.  * mf_fullname()    make file name full path (use before first :cd)
  108.  */
  109.  
  110. /*
  111.  * mf_open: open an existing or new memory block file
  112.  *
  113.  *  fname:    name of file to use (NULL means no file at all)
  114.  *        Note: fname must have been allocated, it is not copied!
  115.  *            If opening the file fails, fname is freed.
  116.  *  trunc_file:        if TRUE: file should be truncated when opening
  117.  *
  118.  *  If fname != NULL and file cannot be opened, fail.
  119.  *
  120.  * return value: identifier for this memory block file.
  121.  */
  122.     MEMFILE *
  123. mf_open(fname, trunc_file)
  124.     char_u  *fname;
  125.     int        trunc_file;
  126. {
  127.     MEMFILE        *mfp;
  128.     int            i;
  129.     off_t        size;
  130. #if defined(STATFS) && defined(UNIX) && !defined(__QNX__)
  131. # define USE_FSTATFS
  132.     struct STATFS   stf;
  133. #endif
  134.  
  135.     if ((mfp = (MEMFILE *)alloc((unsigned)sizeof(MEMFILE))) == NULL)
  136.     return NULL;
  137.  
  138.     if (fname == NULL)        /* no file for this memfile, use memory only */
  139.     {
  140.     mfp->mf_fname = NULL;
  141.     mfp->mf_ffname = NULL;
  142.     mfp->mf_fd = -1;
  143.     }
  144.     else
  145.     {
  146.     mf_do_open(mfp, fname, trunc_file);    /* try to open the file */
  147.  
  148.     /* if the file cannot be opened, return here */
  149.     if (mfp->mf_fd < 0)
  150.     {
  151.         vim_free(mfp);
  152.         return NULL;
  153.     }
  154.     }
  155.  
  156.     mfp->mf_free_first = NULL;        /* free list is empty */
  157.     mfp->mf_used_first = NULL;        /* used list is empty */
  158.     mfp->mf_used_last = NULL;
  159.     mfp->mf_dirty = FALSE;
  160.     mfp->mf_used_count = 0;
  161.     for (i = 0; i < MEMHASHSIZE; ++i)
  162.     {
  163.     mfp->mf_hash[i] = NULL;        /* hash lists are empty */
  164.     mfp->mf_trans[i] = NULL;    /* trans lists are empty */
  165.     }
  166.     mfp->mf_page_size = MEMFILE_PAGE_SIZE;
  167.  
  168. #ifdef USE_FSTATFS
  169.     /*
  170.      * Try to set the page size equal to the block size of the device.
  171.      * Speeds up I/O a lot.
  172.      * NOTE: minimal block size depends on size of block 0 data! It's not done
  173.      * with a sizeof(), because block 0 is defined in memline.c (Sorry).
  174.      * The maximal block size is arbitrary.
  175.      */
  176.     if (mfp->mf_fd >= 0 &&
  177.             fstatfs(mfp->mf_fd, &stf, sizeof(struct statfs), 0) == 0 &&
  178.             stf.F_BSIZE >= 1048 && stf.F_BSIZE <= 50000)
  179.     mfp->mf_page_size = stf.F_BSIZE;
  180. #endif
  181.  
  182.     if (mfp->mf_fd < 0 || trunc_file ||
  183.              (size = lseek(mfp->mf_fd, (off_t)0L, SEEK_END)) <= 0)
  184.     mfp->mf_blocknr_max = 0;    /* no file or empty file */
  185.     else
  186.     mfp->mf_blocknr_max = size / mfp->mf_page_size;
  187.     mfp->mf_blocknr_min = -1;
  188.     mfp->mf_neg_count = 0;
  189.     mfp->mf_infile_count = mfp->mf_blocknr_max;
  190.     mfp->mf_used_count_max = p_mm * 1024 / mfp->mf_page_size;
  191.  
  192.     return mfp;
  193. }
  194.  
  195. /*
  196.  * mf_open_file: open a file for an existing memfile. Used when updatecount
  197.  *         set from 0 to some value.
  198.  *
  199.  *  fname:    name of file to use (NULL means no file at all)
  200.  *        Note: fname must have been allocated, it is not copied!
  201.  *            If opening the file fails, fname is freed.
  202.  *
  203.  * return value: FAIL if file could not be opened, OK otherwise
  204.  */
  205.     int
  206. mf_open_file(mfp, fname)
  207.     MEMFILE    *mfp;
  208.     char_u    *fname;
  209. {
  210.     mf_do_open(mfp, fname, TRUE);        /* try to open the file */
  211.  
  212.     if (mfp->mf_fd < 0)
  213.     return FAIL;
  214.  
  215.     mfp->mf_dirty = TRUE;
  216.     return OK;
  217. }
  218.  
  219. /*
  220.  * close a memory file and delete the associated file if 'del_file' is TRUE
  221.  */
  222.     void
  223. mf_close(mfp, del_file)
  224.     MEMFILE *mfp;
  225.     int        del_file;
  226. {
  227.     BHDR    *hp, *nextp;
  228.     NR_TRANS    *tp, *tpnext;
  229.     int        i;
  230.  
  231.     if (mfp == NULL)            /* safety check */
  232.     return;
  233.     if (mfp->mf_fd >= 0)
  234.     {
  235.     if (close(mfp->mf_fd) < 0)
  236.         EMSG("Close error on swap file");
  237.     }
  238.     if (del_file && mfp->mf_fname != NULL)
  239.     vim_remove(mfp->mf_fname);
  240.                         /* free entries in used list */
  241.     for (hp = mfp->mf_used_first; hp != NULL; hp = nextp)
  242.     {
  243.     total_mem_used -= hp->bh_page_count * mfp->mf_page_size;
  244.     nextp = hp->bh_next;
  245.     mf_free_bhdr(hp);
  246.     }
  247.     while (mfp->mf_free_first != NULL)        /* free entries in free list */
  248.     vim_free(mf_rem_free(mfp));
  249.     for (i = 0; i < MEMHASHSIZE; ++i)        /* free entries in trans lists */
  250.     for (tp = mfp->mf_trans[i]; tp != NULL; tp = tpnext)
  251.     {
  252.         tpnext = tp->nt_next;
  253.         vim_free(tp);
  254.     }
  255.     vim_free(mfp->mf_fname);
  256.     vim_free(mfp->mf_ffname);
  257.     vim_free(mfp);
  258. }
  259.  
  260. /*
  261.  * get a new block
  262.  *
  263.  *   negative: TRUE if negative block number desired (data block)
  264.  */
  265.     BHDR *
  266. mf_new(mfp, negative, page_count)
  267.     MEMFILE    *mfp;
  268.     int        negative;
  269.     int        page_count;
  270. {
  271.     BHDR    *hp;        /* new BHDR */
  272.     BHDR    *freep;        /* first block in free list */
  273.     char_u  *p;
  274.  
  275.     /*
  276.      * If we reached the maximum size for the used memory blocks, release one
  277.      * If a BHDR is returned, use it and adjust the page_count if necessary.
  278.      */
  279.     hp = mf_release(mfp, page_count);
  280.  
  281. /*
  282.  * Decide on the number to use:
  283.  * If there is a free block, use its number.
  284.  * Otherwise use mf_block_min for a negative number, mf_block_max for
  285.  * a positive number.
  286.  */
  287.     freep = mfp->mf_free_first;
  288.     if (!negative && freep != NULL && freep->bh_page_count >= page_count)
  289.     {
  290.     /*
  291.      * If the block in the free list has more pages, take only the number
  292.      * of pages needed and allocate a new BHDR with data
  293.      *
  294.      * If the number of pages matches and mf_release did not return a BHDR,
  295.      * use the BHDR from the free list and allocate the data
  296.      *
  297.      * If the number of pages matches and mf_release returned a BHDR,
  298.      * just use the number and free the BHDR from the free list
  299.      */
  300.     if (freep->bh_page_count > page_count)
  301.     {
  302.         if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
  303.         return NULL;
  304.         hp->bh_bnum = freep->bh_bnum;
  305.         freep->bh_bnum += page_count;
  306.         freep->bh_page_count -= page_count;
  307.     }
  308.     else if (hp == NULL)        /* need to allocate memory for this block */
  309.     {
  310.         if ((p = (char_u *)alloc(mfp->mf_page_size * page_count)) == NULL)
  311.         return NULL;
  312.         hp = mf_rem_free(mfp);
  313.         hp->bh_data = p;
  314.     }
  315.     else            /* use the number, remove entry from free list */
  316.     {
  317.         freep = mf_rem_free(mfp);
  318.         hp->bh_bnum = freep->bh_bnum;
  319.         vim_free(freep);
  320.     }
  321.     }
  322.     else    /* get a new number */
  323.     {
  324.     if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
  325.         return NULL;
  326.     if (negative)
  327.     {
  328.         hp->bh_bnum = mfp->mf_blocknr_min--;
  329.         mfp->mf_neg_count++;
  330.     }
  331.     else
  332.     {
  333.         hp->bh_bnum = mfp->mf_blocknr_max;
  334.         mfp->mf_blocknr_max += page_count;
  335.     }
  336.     }
  337.     hp->bh_flags = BH_LOCKED | BH_DIRTY;    /* new block is always dirty */
  338.     mfp->mf_dirty = TRUE;
  339.     hp->bh_page_count = page_count;
  340.     mf_ins_used(mfp, hp);
  341.     mf_ins_hash(mfp, hp);
  342.  
  343.     /*
  344.      * Init the data to all zero, to avoid reading uninitialized data.
  345.      * This also avoids that the passwd file ends up in the swap file!
  346.      */
  347.     (void)vim_memset((char *)(hp->bh_data), 0, (size_t)mfp->mf_page_size);
  348.  
  349.     return hp;
  350. }
  351.  
  352. /*
  353.  * get existing block 'nr' with 'page_count' pages
  354.  *
  355.  * Note: The caller should first check a negative nr with mf_trans_del()
  356.  */
  357.     BHDR *
  358. mf_get(mfp, nr, page_count)
  359.     MEMFILE    *mfp;
  360.     blocknr_t    nr;
  361.     int        page_count;
  362. {
  363.     BHDR    *hp;
  364.                         /* doesn't exist */
  365.     if (nr >= mfp->mf_blocknr_max || nr <= mfp->mf_blocknr_min)
  366.     return NULL;
  367.  
  368.     /*
  369.      * see if it is in the cache
  370.      */
  371.     hp = mf_find_hash(mfp, nr);
  372.     if (hp == NULL)    /* not in the hash list */
  373.     {
  374.     if (nr < 0 || nr >= mfp->mf_infile_count)   /* can't be in the file */
  375.         return NULL;
  376.  
  377.     /* could check here if the block is in the free list */
  378.  
  379.     /*
  380.      * Check if we need to flush an existing block.
  381.      * If so, use that block.
  382.      * If not, allocate a new block.
  383.      */
  384.     hp = mf_release(mfp, page_count);
  385.     if (hp == NULL && (hp = mf_alloc_bhdr(mfp, page_count)) == NULL)
  386.         return NULL;
  387.  
  388.     hp->bh_bnum = nr;
  389.     hp->bh_flags = 0;
  390.     hp->bh_page_count = page_count;
  391.     if (mf_read(mfp, hp) == FAIL)        /* cannot read the block! */
  392.     {
  393.         mf_free_bhdr(hp);
  394.         return NULL;
  395.     }
  396.     }
  397.     else
  398.     {
  399.     mf_rem_used(mfp, hp);    /* remove from list, insert in front below */
  400.     mf_rem_hash(mfp, hp);
  401.     }
  402.  
  403.     hp->bh_flags |= BH_LOCKED;
  404.     mf_ins_used(mfp, hp);    /* put in front of used list */
  405.     mf_ins_hash(mfp, hp);    /* put in front of hash list */
  406.  
  407.     return hp;
  408. }
  409.  
  410. /*
  411.  * release the block *hp
  412.  *
  413.  *   dirty: Block must be written to file later
  414.  *   infile: Block should be in file (needed for recovery)
  415.  *
  416.  *  no return value, function cannot fail
  417.  */
  418.     void
  419. mf_put(mfp, hp, dirty, infile)
  420.     MEMFILE *mfp;
  421.     BHDR    *hp;
  422.     int        dirty;
  423.     int        infile;
  424. {
  425.     int        flags;
  426.  
  427.     flags = hp->bh_flags;
  428.  
  429.     if ((flags & BH_LOCKED) == 0)
  430.     EMSG("block was not locked");
  431.     flags &= ~BH_LOCKED;
  432.     if (dirty)
  433.     {
  434.     flags |= BH_DIRTY;
  435.     mfp->mf_dirty = TRUE;
  436.     }
  437.     hp->bh_flags = flags;
  438.     if (infile)
  439.     mf_trans_add(mfp, hp);        /* may translate negative in positive nr */
  440. }
  441.  
  442. /*
  443.  * block *hp is no longer in used, may put it in the free list of memfile *mfp
  444.  */
  445.     void
  446. mf_free(mfp, hp)
  447.     MEMFILE *mfp;
  448.     BHDR    *hp;
  449. {
  450.     vim_free(hp->bh_data);    /* free the memory */
  451.     mf_rem_hash(mfp, hp);    /* get *hp out of the hash list */
  452.     mf_rem_used(mfp, hp);    /* get *hp out of the used list */
  453.     if (hp->bh_bnum < 0)
  454.     {
  455.     vim_free(hp);        /* don't want negative numbers in free list */
  456.     mfp->mf_neg_count--;
  457.     }
  458.     else
  459.     mf_ins_free(mfp, hp);    /* put *hp in the free list */
  460. }
  461.  
  462. /*
  463.  * Sync the memory file *mfp to disk.
  464.  * Flags:
  465.  *  MFS_ALL    If not given, blocks with negative numbers are not synced,
  466.  *        even when they are dirty!
  467.  *  MFS_STOP    Stop syncing when a character becomes available, but sync at
  468.  *        least one block.
  469.  *  MFS_FLUSH    Make sure buffers are flushed to disk, so they will survive a
  470.  *        system crash.
  471.  *  MFS_ZERO    Only write block 0.
  472.  *
  473.  * Return FAIL for failure, OK otherwise
  474.  */
  475.     int
  476. mf_sync(mfp, flags)
  477.     MEMFILE *mfp;
  478.     int        flags;
  479. {
  480.     int        status;
  481.     BHDR    *hp;
  482. #ifdef SYNC_DUP_CLOSE
  483.     int        fd;
  484. #endif
  485.  
  486.     if (mfp->mf_fd < 0)        /* there is no file, nothing to do */
  487.     {
  488.     mfp->mf_dirty = FALSE;
  489.     return FAIL;
  490.     }
  491.  
  492.     /*
  493.      * sync from last to first (may reduce the probability of an inconsistent
  494.      * file) If a write fails, it is very likely caused by a full filesystem.
  495.      * Then we only try to write blocks within the existing file. If that also
  496.      * fails then we give up.
  497.      */
  498.     status = OK;
  499.     for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
  500.     if (((flags & MFS_ALL) || hp->bh_bnum >= 0)
  501.         && (hp->bh_flags & BH_DIRTY)
  502.         && (status == OK || (hp->bh_bnum >= 0
  503.             && hp->bh_bnum < mfp->mf_infile_count)))
  504.     {
  505.         if ((flags & MFS_ZERO) && hp->bh_bnum != 0)
  506.         continue;
  507.         if (mf_write(mfp, hp) == FAIL)
  508.         {
  509.         if (status == FAIL)    /* double error: quit syncing */
  510.             break;
  511.         status = FAIL;
  512.         }
  513.         /* Stop when char available now */
  514.         if ((flags & MFS_STOP) && ui_char_avail())
  515.         break;
  516.     }
  517.  
  518.     /*
  519.      * If the whole list is flushed, the memfile is not dirty anymore.
  520.      * In case of an error this flag is also set, to avoid trying all the time.
  521.      */
  522.     if (hp == NULL || status == FAIL)
  523.     mfp->mf_dirty = FALSE;
  524.  
  525.     if ((flags & MFS_FLUSH) && *p_sws != NUL)
  526.     {
  527. #if defined(UNIX)
  528. # ifdef HAVE_FSYNC
  529.     /*
  530.      * most Unixes have the very useful fsync() function, just what we need.
  531.      * However, with OS/2 and EMX it is also available, but there are
  532.      * reports of bad problems with it (a bug in HPFS.IFS).
  533.      * So we disable use of it here in case someone tries to be smart
  534.      * and changes os_os2_cfg.h... (even though there is no __EMX__ test
  535.      * in the #if, as __EMX__ does not have sync(); we hope for a timely
  536.      * sync from the system itself).
  537.      */
  538. #  if defined(__EMX__)
  539.    error "Dont use fsync with EMX! Read emxdoc.doc or emxfix01.doc for info."
  540. #  endif
  541.     if (STRCMP(p_sws, "fsync") == 0)
  542.     {
  543.         if (fsync(mfp->mf_fd))
  544.         status = FAIL;
  545.     }
  546.     else
  547. # endif
  548. # ifdef __OPENNT
  549.         fflush(NULL);    /* OpenNT is strictly POSIX (Benzinger) */
  550. # else
  551.         sync();
  552. # endif
  553. #endif
  554. #ifdef MSDOS
  555.     if (_dos_commit(mfp->mf_fd))
  556.         status = FAIL;
  557. #else
  558. # ifdef SYNC_DUP_CLOSE
  559.     /*
  560.      * Win32 is a bit more work: Duplicate the file handle and close it.
  561.      * This should flush the file to disk.
  562.      */
  563.     if ((fd = dup(mfp->mf_fd)) >= 0)
  564.         close(fd);
  565. # endif
  566. #endif
  567. #ifdef AMIGA
  568.     /*
  569.      * Flush() only exists for AmigaDos 2.0.
  570.      * For 1.3 it should be done with close() + open(), but then the risk
  571.      * is that the open() may fail and lose the file....
  572.      */
  573. # ifndef NO_ARP
  574.     if (dos2)
  575. # endif
  576. # ifdef SASC
  577.     {
  578.         struct UFB *fp = chkufb(mfp->mf_fd);
  579.  
  580.         if (fp != NULL)
  581.         Flush(fp->ufbfh);
  582.     }
  583. # else
  584. #  ifdef _DCC
  585.     {
  586.         BPTR fh = (BPTR)fdtofh(mfp->mf_fd);
  587.  
  588.         if (fh != 0)
  589.         Flush(fh);
  590.         }
  591. #  else /* assume Manx */
  592.         Flush(_devtab[mfp->mf_fd].fd);
  593. #  endif
  594. # endif
  595. #endif /* AMIGA */
  596.     }
  597.  
  598.     return status;
  599. }
  600.  
  601. /*
  602.  * insert block *hp in front of hashlist of memfile *mfp
  603.  */
  604.     static void
  605. mf_ins_hash(mfp, hp)
  606.     MEMFILE *mfp;
  607.     BHDR    *hp;
  608. {
  609.     BHDR    *hhp;
  610.     int        hash;
  611.  
  612.     hash = MEMHASH(hp->bh_bnum);
  613.     hhp = mfp->mf_hash[hash];
  614.     hp->bh_hash_next = hhp;
  615.     hp->bh_hash_prev = NULL;
  616.     if (hhp != NULL)
  617.     hhp->bh_hash_prev = hp;
  618.     mfp->mf_hash[hash] = hp;
  619. }
  620.  
  621. /*
  622.  * remove block *hp from hashlist of memfile list *mfp
  623.  */
  624.     static void
  625. mf_rem_hash(mfp, hp)
  626.     MEMFILE *mfp;
  627.     BHDR    *hp;
  628. {
  629.     if (hp->bh_hash_prev == NULL)
  630.     mfp->mf_hash[MEMHASH(hp->bh_bnum)] = hp->bh_hash_next;
  631.     else
  632.     hp->bh_hash_prev->bh_hash_next = hp->bh_hash_next;
  633.  
  634.     if (hp->bh_hash_next)
  635.     hp->bh_hash_next->bh_hash_prev = hp->bh_hash_prev;
  636. }
  637.  
  638. /*
  639.  * look in hash lists of memfile *mfp for block header with number 'nr'
  640.  */
  641.     static BHDR *
  642. mf_find_hash(mfp, nr)
  643.     MEMFILE    *mfp;
  644.     blocknr_t    nr;
  645. {
  646.     BHDR    *hp;
  647.  
  648.     for (hp = mfp->mf_hash[MEMHASH(nr)]; hp != NULL; hp = hp->bh_hash_next)
  649.     if (hp->bh_bnum == nr)
  650.         break;
  651.     return hp;
  652. }
  653.  
  654. /*
  655.  * insert block *hp in front of used list of memfile *mfp
  656.  */
  657.     static void
  658. mf_ins_used(mfp, hp)
  659.     MEMFILE *mfp;
  660.     BHDR    *hp;
  661. {
  662.     hp->bh_next = mfp->mf_used_first;
  663.     mfp->mf_used_first = hp;
  664.     hp->bh_prev = NULL;
  665.     if (hp->bh_next == NULL)        /* list was empty, adjust last pointer */
  666.     mfp->mf_used_last = hp;
  667.     else
  668.     hp->bh_next->bh_prev = hp;
  669.     mfp->mf_used_count += hp->bh_page_count;
  670.     total_mem_used += hp->bh_page_count * mfp->mf_page_size;
  671. }
  672.  
  673. /*
  674.  * remove block *hp from used list of memfile *mfp
  675.  */
  676.     static void
  677. mf_rem_used(mfp, hp)
  678.     MEMFILE *mfp;
  679.     BHDR    *hp;
  680. {
  681.     if (hp->bh_next == NULL)        /* last block in used list */
  682.     mfp->mf_used_last = hp->bh_prev;
  683.     else
  684.     hp->bh_next->bh_prev = hp->bh_prev;
  685.     if (hp->bh_prev == NULL)        /* first block in used list */
  686.     mfp->mf_used_first = hp->bh_next;
  687.     else
  688.     hp->bh_prev->bh_next = hp->bh_next;
  689.     mfp->mf_used_count -= hp->bh_page_count;
  690.     total_mem_used -= hp->bh_page_count * mfp->mf_page_size;
  691. }
  692.  
  693. /*
  694.  * Release the least recently used block from the used list if the number
  695.  * of used memory blocks gets to big.
  696.  *
  697.  * Return the block header to the caller, including the memory block, so
  698.  * it can be re-used. Make sure the page_count is right.
  699.  */
  700.     static BHDR *
  701. mf_release(mfp, page_count)
  702.     MEMFILE    *mfp;
  703.     int        page_count;
  704. {
  705.     BHDR    *hp;
  706.     int        need_release;
  707.     BUF        *buf;
  708.  
  709.     /*
  710.      * Need to release a block if the number of blocks for this memfile is
  711.      * higher than the maximum or total memory used is over 'maxmemtot'
  712.      */
  713.     need_release = ((mfp->mf_used_count >= mfp->mf_used_count_max)
  714.                   || (total_mem_used >> 10) >= (long_u)p_mmt);
  715.  
  716.     /*
  717.      * Try to create a swap file if the amount of memory used is getting too
  718.      * high.
  719.      */
  720.     if (mfp->mf_fd < 0 && need_release && p_uc)
  721.     {
  722.     /* find for which buffer this memfile is */
  723.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  724.         if (buf->b_ml.ml_mfp == mfp)
  725.         break;
  726.     if (buf != NULL && buf->b_may_swap)
  727.         ml_open_file(buf);
  728.     }
  729.  
  730.     /*
  731.      * don't release a block if
  732.      *    there is no file for this memfile
  733.      * or
  734.      *    the number of blocks for this memfile is lower than the maximum
  735.      *      and
  736.      *    total memory used is not up to 'maxmemtot'
  737.      */
  738.     if (mfp->mf_fd < 0 || !need_release)
  739.     return NULL;
  740.  
  741.     for (hp = mfp->mf_used_last; hp != NULL; hp = hp->bh_prev)
  742.     if (!(hp->bh_flags & BH_LOCKED))
  743.         break;
  744.     if (hp == NULL)    /* not a single one that can be released */
  745.     return NULL;
  746.  
  747.     /*
  748.      * If the block is dirty, write it.
  749.      * If the write fails we don't free it.
  750.      */
  751.     if ((hp->bh_flags & BH_DIRTY) && mf_write(mfp, hp) == FAIL)
  752.     return NULL;
  753.  
  754.     mf_rem_used(mfp, hp);
  755.     mf_rem_hash(mfp, hp);
  756.  
  757.     /*
  758.      * If a BHDR is returned, make sure that the page_count of bh_data is right
  759.      */
  760.     if (hp->bh_page_count != page_count)
  761.     {
  762.     vim_free(hp->bh_data);
  763.     if ((hp->bh_data = alloc(mfp->mf_page_size * page_count)) == NULL)
  764.     {
  765.         vim_free(hp);
  766.         return NULL;
  767.     }
  768.     hp->bh_page_count = page_count;
  769.     }
  770.     return hp;
  771. }
  772.  
  773. /*
  774.  * release as many blocks as possible
  775.  * Used in case of out of memory
  776.  *
  777.  * return TRUE if any memory was released
  778.  */
  779.     int
  780. mf_release_all()
  781. {
  782.     BUF        *buf;
  783.     MEMFILE    *mfp;
  784.     BHDR    *hp;
  785.     int        retval = FALSE;
  786.  
  787.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  788.     {
  789.     mfp = buf->b_ml.ml_mfp;
  790.     /* only if there is a memfile with a file */
  791.     if (mfp != NULL && mfp->mf_fd >= 0)
  792.         for (hp = mfp->mf_used_last; hp != NULL; )
  793.         {
  794.         if (!(hp->bh_flags & BH_LOCKED) && (!(hp->bh_flags & BH_DIRTY)
  795.                         || mf_write(mfp, hp) != FAIL))
  796.         {
  797.             mf_rem_used(mfp, hp);
  798.             mf_rem_hash(mfp, hp);
  799.             mf_free_bhdr(hp);
  800.             hp = mfp->mf_used_last;    /* re-start, list was changed */
  801.             retval = TRUE;
  802.         }
  803.         else
  804.             hp = hp->bh_prev;
  805.         }
  806.     }
  807.     return retval;
  808. }
  809.  
  810. /*
  811.  * Allocate a block header and a block of memory for it
  812.  */
  813.     static BHDR *
  814. mf_alloc_bhdr(mfp, page_count)
  815.     MEMFILE    *mfp;
  816.     int        page_count;
  817. {
  818.     BHDR    *hp;
  819.  
  820.     if ((hp = (BHDR *)alloc((unsigned)sizeof(BHDR))) != NULL)
  821.     {
  822.     if ((hp->bh_data = (char_u *)alloc(mfp->mf_page_size * page_count))
  823.                                       == NULL)
  824.     {
  825.         vim_free(hp);        /* not enough memory */
  826.         return NULL;
  827.     }
  828.     hp->bh_page_count = page_count;
  829.     }
  830.     return hp;
  831. }
  832.  
  833. /*
  834.  * Free a block header and the block of memory for it
  835.  */
  836.     static void
  837. mf_free_bhdr(hp)
  838.     BHDR    *hp;
  839. {
  840.     vim_free(hp->bh_data);
  841.     vim_free(hp);
  842. }
  843.  
  844. /*
  845.  * insert entry *hp in the free list
  846.  */
  847.     static void
  848. mf_ins_free(mfp, hp)
  849.     MEMFILE *mfp;
  850.     BHDR    *hp;
  851. {
  852.     hp->bh_next = mfp->mf_free_first;
  853.     mfp->mf_free_first = hp;
  854. }
  855.  
  856. /*
  857.  * remove the first entry from the free list and return a pointer to it
  858.  * Note: caller must check that mfp->mf_free_first is not NULL!
  859.  */
  860.     static BHDR *
  861. mf_rem_free(mfp)
  862.     MEMFILE *mfp;
  863. {
  864.     BHDR    *hp;
  865.  
  866.     hp = mfp->mf_free_first;
  867.     mfp->mf_free_first = hp->bh_next;
  868.     return hp;
  869. }
  870.  
  871. /*
  872.  * read a block from disk
  873.  *
  874.  * Return FAIL for failure, OK otherwise
  875.  */
  876.     static int
  877. mf_read(mfp, hp)
  878.     MEMFILE    *mfp;
  879.     BHDR    *hp;
  880. {
  881.     off_t    offset;
  882.     unsigned    page_size;
  883.     unsigned    size;
  884.  
  885.     if (mfp->mf_fd < 0)        /* there is no file, can't read */
  886.     return FAIL;
  887.  
  888.     page_size = mfp->mf_page_size;
  889.     offset = page_size * hp->bh_bnum;
  890.     size = page_size * hp->bh_page_count;
  891.     if (lseek(mfp->mf_fd, offset, SEEK_SET) != offset)
  892.     {
  893.     EMSG("Seek error in swap file read");
  894.     return FAIL;
  895.     }
  896.     if ((unsigned)read(mfp->mf_fd, (char *)hp->bh_data, (size_t)size) != size)
  897.     {
  898.     EMSG("Read error in swap file");
  899.     return FAIL;
  900.     }
  901.     return OK;
  902. }
  903.  
  904. /*
  905.  * write a block to disk
  906.  *
  907.  * Return FAIL for failure, OK otherwise
  908.  */
  909.     static int
  910. mf_write(mfp, hp)
  911.     MEMFILE    *mfp;
  912.     BHDR    *hp;
  913. {
  914.     off_t    offset;        /* offset in the file */
  915.     blocknr_t    nr;        /* block nr which is being written */
  916.     BHDR    *hp2;
  917.     unsigned    page_size;  /* number of bytes in a page */
  918.     unsigned    page_count; /* number of pages written */
  919.     unsigned    size;        /* number of bytes written */
  920.  
  921.     if (mfp->mf_fd < 0)        /* there is no file, can't write */
  922.     return FAIL;
  923.  
  924.     if (hp->bh_bnum < 0)    /* must assign file block number */
  925.     if (mf_trans_add(mfp, hp) == FAIL)
  926.         return FAIL;
  927.  
  928.     page_size = mfp->mf_page_size;
  929.  
  930.     /*
  931.      * We don't want gaps in the file. Write the blocks in front of *hp
  932.      * to extend the file.
  933.      * If block 'mf_infile_count' is not in the hash list, it has been
  934.      * freed. Fill the space in the file with data from the current block.
  935.      */
  936.     for (;;)
  937.     {
  938.     nr = hp->bh_bnum;
  939.     if (nr > mfp->mf_infile_count)        /* beyond end of file */
  940.     {
  941.         nr = mfp->mf_infile_count;
  942.         hp2 = mf_find_hash(mfp, nr);    /* NULL catched below */
  943.     }
  944.     else
  945.         hp2 = hp;
  946.  
  947.     offset = page_size * nr;
  948.     if (lseek(mfp->mf_fd, offset, SEEK_SET) != offset)
  949.     {
  950.         EMSG("Seek error in swap file write");
  951.         return FAIL;
  952.     }
  953.     if (hp2 == NULL)        /* freed block, fill with dummy data */
  954.         page_count = 1;
  955.     else
  956.         page_count = hp2->bh_page_count;
  957.     size = page_size * page_count;
  958.     if ((unsigned)write(mfp->mf_fd,
  959.          (char *)(hp2 == NULL ? hp : hp2)->bh_data, (size_t)size) != size)
  960.     {
  961.         /*
  962.          * Avoid repeating the error message, this mostly happens when the
  963.          * disk is full. We give the message again only after a succesful
  964.          * write or when hitting a key. We keep on trying, in case some
  965.          * space becomes available.
  966.          */
  967.         if (!did_swapwrite_msg)
  968.         EMSG("Write error in swap file");
  969.         did_swapwrite_msg = TRUE;
  970.         return FAIL;
  971.     }
  972.     did_swapwrite_msg = FALSE;
  973.     if (hp2 != NULL)            /* written a non-dummy block */
  974.         hp2->bh_flags &= ~BH_DIRTY;
  975.                         /* appended to the file */
  976.     if (nr + (blocknr_t)page_count > mfp->mf_infile_count)
  977.         mfp->mf_infile_count = nr + page_count;
  978.     if (nr == hp->bh_bnum)            /* written the desired block */
  979.         break;
  980.     }
  981.     return OK;
  982. }
  983.  
  984. /*
  985.  * Make block number for *hp positive and add it to the translation list
  986.  *
  987.  * Return FAIL for failure, OK otherwise
  988.  */
  989.     static int
  990. mf_trans_add(mfp, hp)
  991.     MEMFILE *mfp;
  992.     BHDR    *hp;
  993. {
  994.     BHDR    *freep;
  995.     blocknr_t    new_bnum;
  996.     int        hash;
  997.     NR_TRANS    *np;
  998.     int        page_count;
  999.  
  1000.     if (hp->bh_bnum >= 0)            /* it's already positive */
  1001.     return OK;
  1002.  
  1003.     if ((np = (NR_TRANS *)alloc((unsigned)sizeof(NR_TRANS))) == NULL)
  1004.     return FAIL;
  1005.  
  1006. /*
  1007.  * get a new number for the block.
  1008.  * If the first item in the free list has sufficient pages, use its number
  1009.  * Otherwise use mf_blocknr_max.
  1010.  */
  1011.     freep = mfp->mf_free_first;
  1012.     page_count = hp->bh_page_count;
  1013.     if (freep != NULL && freep->bh_page_count >= page_count)
  1014.     {
  1015.     new_bnum = freep->bh_bnum;
  1016.     /*
  1017.      * If the page count of the free block was larger, recude it.
  1018.      * If the page count matches, remove the block from the free list
  1019.      */
  1020.     if (freep->bh_page_count > page_count)
  1021.     {
  1022.         freep->bh_bnum += page_count;
  1023.         freep->bh_page_count -= page_count;
  1024.     }
  1025.     else
  1026.     {
  1027.         freep = mf_rem_free(mfp);
  1028.         vim_free(freep);
  1029.     }
  1030.     }
  1031.     else
  1032.     {
  1033.     new_bnum = mfp->mf_blocknr_max;
  1034.     mfp->mf_blocknr_max += page_count;
  1035.     }
  1036.  
  1037.     np->nt_old_bnum = hp->bh_bnum;        /* adjust number */
  1038.     np->nt_new_bnum = new_bnum;
  1039.  
  1040.     mf_rem_hash(mfp, hp);            /* remove from old hash list */
  1041.     hp->bh_bnum = new_bnum;
  1042.     mf_ins_hash(mfp, hp);            /* insert in new hash list */
  1043.  
  1044.     hash = MEMHASH(np->nt_old_bnum);        /* insert in trans list */
  1045.     np->nt_next = mfp->mf_trans[hash];
  1046.     mfp->mf_trans[hash] = np;
  1047.     if (np->nt_next != NULL)
  1048.     np->nt_next->nt_prev = np;
  1049.     np->nt_prev = NULL;
  1050.  
  1051.     return OK;
  1052. }
  1053.  
  1054. /*
  1055.  * Lookup a tranlation from the trans lists and delete the entry
  1056.  *
  1057.  * Return the positive new number when found, the old number when not found
  1058.  */
  1059.     blocknr_t
  1060. mf_trans_del(mfp, old_nr)
  1061.     MEMFILE    *mfp;
  1062.     blocknr_t    old_nr;
  1063. {
  1064.     int        hash;
  1065.     NR_TRANS    *np;
  1066.     blocknr_t    new_bnum;
  1067.  
  1068.     hash = MEMHASH(old_nr);
  1069.     for (np = mfp->mf_trans[hash]; np != NULL; np = np->nt_next)
  1070.     if (np->nt_old_bnum == old_nr)
  1071.         break;
  1072.     if (np == NULL)        /* not found */
  1073.     return old_nr;
  1074.  
  1075.     mfp->mf_neg_count--;
  1076.     new_bnum = np->nt_new_bnum;
  1077.     if (np->nt_prev != NULL)        /* remove entry from the trans list */
  1078.     np->nt_prev->nt_next = np->nt_next;
  1079.     else
  1080.     mfp->mf_trans[hash] = np->nt_next;
  1081.     if (np->nt_next != NULL)
  1082.     np->nt_next->nt_prev = np->nt_prev;
  1083.     vim_free(np);
  1084.  
  1085.     return new_bnum;
  1086. }
  1087.  
  1088. /*
  1089.  * Set mfp->mf_ffname according to mfp->mf_fname and some other things.
  1090.  * Only called when creating or renaming the swapfile.    Either way it's a new
  1091.  * name so we must work out the full path name.
  1092.  */
  1093.     void
  1094. mf_set_ffname(mfp)
  1095.     MEMFILE    *mfp;
  1096. {
  1097.     mfp->mf_ffname = FullName_save(mfp->mf_fname, FALSE);
  1098. }
  1099.  
  1100. /*
  1101.  * Make the name of the file used for the memfile a full path.
  1102.  * Used before doing a :cd
  1103.  */
  1104.     void
  1105. mf_fullname(mfp)
  1106.     MEMFILE    *mfp;
  1107. {
  1108.     if (mfp != NULL && mfp->mf_fname != NULL && mfp->mf_ffname != NULL)
  1109.     {
  1110.     vim_free(mfp->mf_fname);
  1111.     mfp->mf_fname = mfp->mf_ffname;
  1112.     mfp->mf_ffname = NULL;
  1113.     }
  1114. }
  1115.  
  1116. /*
  1117.  * return TRUE if there are any translations pending for 'mfp'
  1118.  */
  1119.     int
  1120. mf_need_trans(mfp)
  1121.     MEMFILE    *mfp;
  1122. {
  1123.     return (mfp->mf_fname != NULL && mfp->mf_neg_count > 0);
  1124. }
  1125.  
  1126. /*
  1127.  * Open a swap file for a memfile.
  1128.  * The "fname" must be in allocated memory, and is consumed (also when an
  1129.  * error occurs).
  1130.  */
  1131.     static void
  1132. mf_do_open(mfp, fname, trunc_file)
  1133.     MEMFILE    *mfp;
  1134.     char_u    *fname;
  1135.     int        trunc_file;
  1136. {
  1137.     mfp->mf_fname = fname;
  1138.     /*
  1139.      * Get the full path name before the open, because this is
  1140.      * not possible after the open on the Amiga.
  1141.      * fname cannot be NameBuff, because it must have been allocated.
  1142.      */
  1143.     mf_set_ffname(mfp);
  1144. #if defined(MSDOS) || defined(WIN32)
  1145.     /*
  1146.      * A ":!cd e:xxx" may change the directory without us knowning, use the
  1147.      * full pathname always.  Careful: This frees fname!
  1148.      */
  1149.     mf_fullname(mfp);
  1150. #endif
  1151.  
  1152.     /*
  1153.      * try to open the file
  1154.      */
  1155.     mfp->mf_fd = open((char *)mfp->mf_fname,
  1156.         (trunc_file ? (O_CREAT | O_RDWR | O_TRUNC) : (O_RDONLY)) | O_EXTRA
  1157. #ifdef UNIX            /* open in rw------- mode */
  1158.             , (mode_t)0600
  1159. #endif
  1160. #if defined(MSDOS) || defined(WIN32) || defined(__EMX__)
  1161.             , S_IREAD | S_IWRITE     /* open read/write */
  1162. #endif
  1163. #ifdef VMS            /* open in rw------- mode */
  1164.             , 0600
  1165. #endif
  1166.             );
  1167.  
  1168.     /*
  1169.      * If the file cannot be opened, use memory only
  1170.      */
  1171.     if (mfp->mf_fd < 0)
  1172.     {
  1173.     vim_free(mfp->mf_fname);
  1174.     vim_free(mfp->mf_ffname);
  1175.     mfp->mf_fname = NULL;
  1176.     mfp->mf_ffname = NULL;
  1177.     }
  1178.     else
  1179.     mch_hide(mfp->mf_fname);    /* try setting the 'hidden' flag */
  1180. }
  1181.